package com.example.demo1.samplews;

import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.File;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class OKHttpUtil {

    static Logger log = LoggerFactory.getLogger(OKHttpUtil.class);

    //===================================绕过SSL验证
    static SSLContext sslContext;

    static SSLSocketFactory sslSocketFactory;

    static TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[]{};
                }

                @Override
                public void checkClientTrusted(
                        X509Certificate[] chain, String authType) {
                }

                @Override
                public void checkServerTrusted(
                        X509Certificate[] chain, String authType) {
                }
            }
    };

    static HostnameVerifier allHostsValid = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true; // Don't check host names
        }
    };

    static final TrustManager[] TRUST_ALL_CERTS = new TrustManager[]{
            new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    // Accept any client cert
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    // Accept any server cert
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[]{};
                }
            }
    };

    static {
        try {
            OKHttpUtil.sslContext = SSLContext.getInstance("SSL");
            OKHttpUtil.sslContext.init(null, TRUST_ALL_CERTS, new java.security.SecureRandom());
            OKHttpUtil.sslSocketFactory = sslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            throw new RuntimeException(e);
        }
    }
    //===================================绕过SSL验证

    /**
     * 兼容不规范格式
     */
    private static String completeUrl(String url) {
        if (url.contains("http")) {
            return url;
        }
        return "http://" + url;
    }

    /**
     * @param url
     * @param jsonParams json格式请求体
     * @param headers    http请求头
     * @return
     */
    public static String postJsonParams(String url, String jsonParams, Map<String, String> headers) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
        Request.Builder build = new Request.Builder().url(url).post(requestBody);
        if (headers != null && headers.size() > 0) {
            headers.forEach((k, v) -> build.addHeader(k, v));
        }
        Request request = build.build();
        return doRequest(request, url);
    }

    public static String postJsonParams(String url, String jsonParams) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        return doRequest(request, url);
    }

    public static Response postJsonParamsRsp(String url, String jsonParams) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        return doRequestRsp(request, url);
    }

    public static String getJsonParams(String url) {
        Request request = new Request.Builder().url(url).get().build();
        return doRequest(request, url);
    }

    public static String getJsonParams(String url, Map<String, String> headers) {
        Request.Builder build = new Request.Builder().url(url).get();
        if (headers != null && headers.size() > 0) {
            headers.forEach((k, v) -> build.addHeader(k, v));
        }
        Request request = build.build();
        return doRequest(request, url);
    }

    public static String deleteJsonParams(String url, String jsonParams, Map<String, String> headers) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
        Request.Builder build = new Request.Builder().url(url).delete(requestBody);
        if (headers != null && headers.size() > 0) {
            headers.forEach((k, v) -> build.addHeader(k, v));
        }
        Request request = build.build();
        return doRequest(request, url);
    }

    public static Response getOutputStream (String url, String jsonParams) throws IOException {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
        Request.Builder build = new Request.Builder().url(url).post(requestBody);
        Request request = build.build();
        OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
        //===================================绕过SSL验证
        builder.connectTimeout(10, TimeUnit.SECONDS).readTimeout(1000, TimeUnit.SECONDS);
        OkHttpClient okHttpClient = builder.build();
        Long start = System.currentTimeMillis();
        Response response = okHttpClient.newCall(request).execute();
        return response;
    }

    private static String doRequest(Request request, String url) {
        url = completeUrl(url);
        String responseBody;
        Response response = null;
        long startTime = System.currentTimeMillis();
        try {

            OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
            //===================================绕过SSL验证
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]).connectTimeout(1000, TimeUnit.SECONDS).readTimeout(1000, TimeUnit.SECONDS);
            builder.setHostnameVerifier$okhttp(allHostsValid);
            OkHttpClient okHttpClient = builder.build();
            Long start = System.currentTimeMillis();
            response = okHttpClient.newCall(request).execute();
            Long end = System.currentTimeMillis();
            int status = response.code();

            if (!response.isSuccessful()) {
                log.error("service return error：{} url:{}", status, url);
            }
            if (response.body() != null) {
                responseBody = response.body().string();
                log.debug("return：{}", responseBody);
                return responseBody;
            } else {
                log.error("service return error：{} url:{}", status, url);
                return null;
            }
        } catch (SocketTimeoutException e) {
            log.error("service time out please check [" + url + "] is ok", e);
            responseBody = "{'code':1,'msg':'service time out" + url + "'}";
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            responseBody = "{'code':1,'msg':'service request exception" + url + "'}";
        } finally {
            log.info("url:[{}] service cost time：{}", url, System.currentTimeMillis() - startTime);
            if (response != null) {
                response.close();
            }
        }
        return responseBody;
    }

    private static Response doRequestRsp(Request request, String url) {
        url = completeUrl(url);
        String responseBody;
        Response response = null;
        long startTime = System.currentTimeMillis();
        try {

            OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
            //===================================绕过SSL验证
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]).connectTimeout(1000, TimeUnit.SECONDS).readTimeout(1000, TimeUnit.SECONDS);
            builder.setHostnameVerifier$okhttp(allHostsValid);
            OkHttpClient okHttpClient = builder.build();
            Long start = System.currentTimeMillis();
            response = okHttpClient.newCall(request).execute();
            Long end = System.currentTimeMillis();
            int status = response.code();

            if (!response.isSuccessful()) {
                log.error("service return error：{} url:{}", status, url);
            }
            return response;
        } catch (SocketTimeoutException e) {
            log.error("service time out please check [" + url + "] is ok", e);
            responseBody = "{'code':1,'msg':'service time out" + url + "'}";
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            responseBody = "{'code':1,'msg':'service request exception" + url + "'}";
        } finally {
            log.info("url:[{}] service cost time：{}", url, System.currentTimeMillis() - startTime);
            if (response != null) {
                response.close();
            }
        }
        return response;
    }

    public static String postInFormBodyWithFiles(String url, Map<String, Object> params) throws Exception {
        url = completeUrl(url);
        OkHttpClient okHttpClient = new OkHttpClient();
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        // 键值对处理
        Iterator<Map.Entry<String, Object>> itera = params.entrySet().iterator();
        while (itera.hasNext()) {
            Map.Entry<String, Object> entry = itera.next();
            String key = entry.getKey();
            Object value = entry.getValue();
            // 普通字符串键值对
            if (value instanceof String) {
                builder.addFormDataPart(key, (String) value);
            }
            // 文件参数处理
            if (value instanceof File) {
                File file = (File) value;
                if (!file.isFile()) {
                    log.info("参数[{}]的值[{}]不是一个有效的文件", key, file.getAbsolutePath());
                    continue;
                }
                String contentType = file.toURL().openConnection().getContentType();
                RequestBody requestBody = RequestBody.create(MediaType.parse(contentType), file);
                String filename = file.getName();
                // 文件名称编码，防止出现中文乱码
                filename = URLEncoder.encode(filename, "UTF-8");
                builder.addFormDataPart(key, filename, requestBody);
            }
            // 文件list键值对
            if (value instanceof List) {
            }
        }

        MultipartBody mBody = builder.build();
        Request request = new Request.Builder().url(url).post(mBody).build();
        Response response = okHttpClient.newCall(request).execute();
        // 结果处理
        if (response.isSuccessful()) {
            return response.body().string();
        } else {
            throw new Exception("Unexpected code :" + response.code() + "|" + response);
        }
    }

    public static JSONObject postFormdata(String url, Map<String, String> formDataMap) throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        //创建body
        MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM); // 表单类型(必填)
        formDataMap.entrySet().stream().forEach(item -> bodyBuilder.addFormDataPart(item.getKey(), item.getValue()));
        RequestBody body = bodyBuilder.build();
        //创建request
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url);
        Request request = requestBuilder.post(body).build();
        //发送请求
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()) {
        }
        //返回响应结果
        return JSONObject.parseObject(response.body().string());
    }

    public static JSONObject postFormdata(String url, Map<String, String> formDataMap, Map<String, String> header) throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        //创建body
        MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM); // 表单类型(必填)
        formDataMap.entrySet().stream().forEach(item -> bodyBuilder.addFormDataPart(item.getKey(), item.getValue()));
        RequestBody body = bodyBuilder.build();
        //创建request
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url);
        if (null != header) {
            header.entrySet().stream().forEach(item -> requestBuilder.header(item.getKey(), item.getValue()));
        }
        Request request = requestBuilder.post(body).build();
        //发送请求
        Response response = okHttpClient.newCall(request).execute();

        //返回响应结果
        return JSONObject.parseObject(response.body().string());
    }



    public static JSONObject queryPaging(String url, Integer pageNo, Integer pageSize) throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        //创建request
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url + "?" + "pageNo=" + pageNo + "&pageSize=" + pageSize);
        Request request = requestBuilder.build();
        //发送请求
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()) {
        }
        //返回响应结果
        return JSONObject.parseObject(response.body().string());
    }

    public static JSONObject queryPaging(String url, Integer pageNo, Integer pageSize, Map<String, String> header) throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        //创建request
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url + "?" + "pageNo=" + pageNo + "&pageSize=" + pageSize);
        header.entrySet().stream().forEach(item -> requestBuilder.header(item.getKey(), item.getValue()));
        Request request = requestBuilder.build();
        //发送请求
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()) {
        }
        //返回响应结果
        return JSONObject.parseObject(response.body().string());
    }

}
